#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <semaphore.h>
#include <vector>

//默认的最大容量
const int max_cap=5;
template <class T>
class RingQueue
{
    //将PV操作封装为函数
    void P(sem_t &tmp)
    {
        sem_wait(&tmp);
    }
    void V(sem_t &tmp)
    {
        sem_post(&tmp);
    }

public:
    //进行环形队列的初始化
    RingQueue(int max_cap) :_max_cap(max_cap), _c_step(0), _p_step(0)
    {
        //初始化数组大小
        _ring_queue.resize(_max_cap);
        //初始化数据个数，开始为0
        sem_init(&_data_sem, 0, 0);
        //初始化空间个数，最开始可用空间为最大空间
        sem_init(&_space_sem, 0, _max_cap);
        //初始化两把锁
        pthread_mutex_init(&_c_mutex,nullptr);
        pthread_mutex_init(&_p_mutex,nullptr);
    }
    //生产者从事生产的函数
    void Push(T &in)
    {
        // 先保证有空间再去竞争锁进行生产
        P(_space_sem); //——V操作 空间 -1
        pthread_mutex_lock(&_p_mutex);//拿到锁

        _ring_queue[_p_step++] = in;
        _p_step %= _max_cap;
        pthread_mutex_unlock(&_p_mutex);//释放锁
        V(_data_sem);// V操作 数据 +1
    }
    //消费者进行消费的函数
    void Pop(T *out)
    {
        //先保证有数据，再去竞争锁去消费
        P(_data_sem);//——P操作，数据 -1
        pthread_mutex_lock(&_c_mutex);//拿到锁
        *out = _ring_queue[_c_step++];
        _c_step %= _max_cap;
        pthread_mutex_unlock(&_c_mutex);//释放锁
        V(_space_sem);//空间 +1
    }
    //释放锁，信号量等一系列事情
    ~RingQueue()
    {
        sem_destroy(&_data_sem);
        sem_destroy(&_space_sem);
        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }

private:
    std::vector<T> _ring_queue;
    int _max_cap;

    //用来表示队头与队尾
    int _c_step;
    int _p_step;

    //定义两个信号量
    sem_t _data_sem;
    sem_t _space_sem;

    //生产消费者各自调用自己的函数，各自用各自的锁
    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
};
